#pragma once
#include <zGraphicsConfig.hpp>
#include <Math/Math.hpp>
#include <Math/Vector3.hpp>

namespace zzz{
/*
Cartesian3DCoord <-> SphericalCoord
\      ^
_\|      |
CubeCoord -> CubeCoordNormalized
everyone use default copy constructor and operator =, all explicit
and provide a operator() to Vector3, implicit
//    ___________
//   /|         /|        Y
//  / |   2    / |        |
// /__|____5_ /  |        |
// |  |      |   |        |________X
// | 1|______|_0_|       /
// |  / 4    |  /       /
// | /    3  | /       /
// |/________|/       Z
//
//           ___
//          |   |
//       ___|_2_|____
//      |   |   |   |
//      |_1_|_5_|_0_|
//          |   |
//          |_3_|
//          |   |
//          |_4_|
//
//  major axis
//  direction     target                  sc     tc    ma
//  ----------    -------------------------------    ---    ---   ---
//  +rx        TEXTURE_CUBE_MAP_POSITIVE_X_ARB    -rz    -ry   rx
//  -rx        TEXTURE_CUBE_MAP_NEGATIVE_X_ARB    +rz    -ry   rx
//  +ry        TEXTURE_CUBE_MAP_POSITIVE_Y_ARB    +rx    +rz   ry
//  -ry        TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB    +rx    -rz   ry
//  +rz        TEXTURE_CUBE_MAP_POSITIVE_Z_ARB    +rx    -ry   rz
//  -rz        TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB    -rx    -ry   rz  
*/
typedef enum {POSX=0,NEGX=1,POSY=2,NEGY=3,POSZ=4,NEGZ=5} CUBEFACE;
template <typename T> struct Cartesian3DCoord;
template <typename T> struct CartesianDirCoord;
template <typename T> struct CubeCoordNormalized;
template <typename T> struct SphericalCoord;

struct ZGRAPHICS_CLASS CubeCoord {
  CUBEFACE cubeface;
  int x,y;
  zsize size;

  CubeCoord();
  CubeCoord(const CUBEFACE _face,const zuint _x,const zuint _y, const zuint _size);
  CubeCoord(const CubeCoord& c);
  const CubeCoord& operator=(const CubeCoord& c);
  inline int ToIndex() const {
    return cubeface*size*size+y*size+x;
  }
  inline void FromIndex(zuint facesize,zuint index) {
    size=facesize;
    cubeface=(CUBEFACE)(index/(size*size));
    y=(index-cubeface*size*size)/size;
    x=index-cubeface*size*size-y*size;
  }
  inline int ToFaceIndex() const {
    return y*size+x;
  }
  inline void FromFaceIndex(zuint facesize,CUBEFACE face,zuint faceindex) {
    size=facesize;
    cubeface=face;
    y=faceindex/size;
    x=faceindex-size*y;
  }
  void Standardize();
};

template <typename T>
struct Cartesian3DCoord : public Vector<3,T> {
  using Vector<3,T>::v;
  Cartesian3DCoord():Vector<3,T>(){}
  Cartesian3DCoord(const T& a,const T& b,const T& c):Vector<3,T>(a,b,c){}
//   //positive and negative
//   inline Cartesian3DCoord<T> operator+() const {return *this;}
//   inline Cartesian3DCoord<T> operator-() const {return Cartesian3DCoord<T>(-v[0],-v[1],-v[2]);}
//   //addition
//   inline Cartesian3DCoord<T> operator+(const Cartesian3DCoord<T> &a) const {return Cartesian3DCoord<T>(v[0]+a.v[0],v[1]+a.v[1],v[2]+a.v[2]);}
//   inline Cartesian3DCoord<T> operator+(const T a) const {return Cartesian3DCoord<T>(v[0]+a,v[1]+a,v[2]+a);}
//   inline void operator+=(const Cartesian3DCoord<T> &a) {v[0]+=a.v[0]; v[1]+=a.v[1]; v[2]+=a.v[2];}
//   inline void operator+=(const T a) {v[0]+=a; v[1]+=a; v[2]+=a;}
//   //subtraction
//   inline Cartesian3DCoord<T> operator-(const Cartesian3DCoord<T> &a) const {return Cartesian3DCoord<T>(v[0]-a.v[0],v[1]-a.v[1],v[2]-a.v[2]);}
//   inline Cartesian3DCoord<T> operator-(const T a) const {return Cartesian3DCoord<T>(v[0]-a,v[1]-a,v[2]-a);}
//   inline void operator-=(const Cartesian3DCoord<T> &a) {v[0]-=a.v[0]; v[1]-=a.v[1]; v[2]-=a.v[2];}
//   inline void operator-=(const T a) {v[0]-=a; v[1]-=a; v[2]-=a;}
//   //multiplication
//   inline VectorBase<3,T> operator*(const Cartesian3DCoord<T> &a) const {return Cartesian3DCoord<T>(v[0]*a.v[0],v[1]*a.v[1],v[2]*a.v[2]);}
//   inline VectorBase<3,T> operator*(const T a) const {return Cartesian3DCoord<T>(v[0]*a,v[1]*a,v[2]*a);}
//   inline void operator*=(const Cartesian3DCoord<T> &a) {v[0]*=a.v[0]; v[1]*=a.v[1]; v[2]*=a.v[2];}
//   inline void operator*=(const T a) {v[0]*=a; v[1]*=a; v[2]*=a;}
//   //division
//   inline Cartesian3DCoord<T> operator/(const Cartesian3DCoord<T> &a) const {return Cartesian3DCoord<T>(v[0]/a.v[0],v[1]/a.v[1],v[2]/a.v[2]);}
//   inline Cartesian3DCoord<T> operator/(const T a) const {return Cartesian3DCoord<T>(v[0]/a,v[1]/a,v[2]/a);}
//   inline void operator/=(const Cartesian3DCoord<T> &a) {v[0]/=a.v[0]; v[1]/=a.v[1]; v[2]/=a.v[2];}
//   inline void operator/=(const T a) {v[0]/=a; v[1]/=a; v[2]/=a;}

  //one number
  Cartesian3DCoord(const T c)
  {
    *this=c;
  }

  const Cartesian3DCoord<T> &operator=(const T c)
  {
    Vector<3,T>::operator =(c);
    return *this;
  }
  //CartesianDirCoord
  template <typename T1>
  Cartesian3DCoord(const CartesianDirCoord<T1> &c)
  {
    *this=c;
  }

  template <typename T1>
  const Cartesian3DCoord<T> &operator=(const CartesianDirCoord<T1> &c)
  {
    v[0]=c.v[0]; v[1]=c.v[1]; v[2]=c.v[2];
    return *this;
  }
  //Vector3
  template <typename T1>
  Cartesian3DCoord(const VectorBase<3,T1> &c)
  {
    *this=c;
  }

  template <typename T1>
  const Cartesian3DCoord<T> &operator=(const VectorBase<3,T1> &c)
  {
    VectorBase<3,T>::operator =(c);
    return *this;
  }
  //SphericalCoord
  template <typename T1>
  const Cartesian3DCoord<T> &operator =(const SphericalCoord<T1> &s)
  {
    v[0]=(T)s.rho*cos(s.phi)*sin(s.theta);
    v[1]=(T)s.rho*sin(s.phi)*sin(s.theta);
    v[2]=(T)s.rho*cos(s.theta);
  }

  template <typename T1>
  Cartesian3DCoord(const SphericalCoord<T1> &s)
  {
    *this=s;
  }
  //CubeCoordNormalized
  template <typename T1>
  const Cartesian3DCoord<T> &operator =(const CubeCoordNormalized<T1> &s)
  {
    switch(s.cubeface)
    {
    case POSX:
      v[0]=0.5f; v[1]=0.5f-s.v; v[2]=0.5f-s.u;
      break;
    case POSY:
      v[0]=-0.5f+s.u; v[1]=0.5f; v[2]=-0.5f+s.v;
      break;
    case POSZ:
      v[0]=-0.5f+s.u; v[1]=0.5f-s.v; v[2]=0.5f;
      break;
    case NEGX:
      v[0]=-0.5f; v[1]=0.5f-s.v; v[2]=-0.5f+s.u;
      break;
    case NEGY:
      v[0]=-0.5f+s.u; v[1]=-0.5f; v[2]=0.5f-s.v;
      break;
    case NEGZ:
      v[0]=0.5f-s.u; v[1]=0.5f-s.v; v[2]=-0.5f;
      break;
    default:
      break;
    }
    return *this;
  }

  template <typename T1>
  Cartesian3DCoord(const CubeCoordNormalized<T1> &s)
  {
    *this=s;
  }
  //CubeCoord
  const Cartesian3DCoord<T> &operator =(const CubeCoord &s)
  {
    T u=(T)((s.x+0.5)/s.size),v=(T)((s.y+0.5)/s.size);
    switch(s.cubeface)
    {
    case POSX:
      v[0]=0.5f; v[1]=0.5f-v; v[2]=0.5f-u;
      break;
    case POSY:
      v[0]=-0.5f+u; v[1]=0.5f; v[2]=-0.5f+v;
      break;
    case POSZ:
      v[0]=-0.5f+u; v[1]=0.5f-v; v[2]=0.5f;
      break;
    case NEGX:
      v[0]=-0.5f; v[1]=0.5f-v; v[2]=-0.5f+u;
      break;
    case NEGY:
      v[0]=-0.5f+u; v[1]=-0.5f; v[2]=0.5f-v;
      break;
    case NEGZ:
      v[0]=0.5f-u; v[1]=0.5f-v; v[2]=-0.5f;
      break;
    default:
      break;
    }
    return *this;
  }

  Cartesian3DCoord(const CubeCoord &s)
  {
    *this=s;
  }
  //Rotate
  template <typename T1>
  void Rotate(T1 *rotatematrix)//column major 4x4
  {
    T w=1;
    T xx,yy,zz,ww;
    xx=rotatematrix[0]*v[0]+rotatematrix[4]*v[1]+rotatematrix[8]*v[2]+rotatematrix[12]*w;
    yy=rotatematrix[1]*v[0]+rotatematrix[5]*v[1]+rotatematrix[9]*v[2]+rotatematrix[13]*w;
    zz=rotatematrix[2]*v[0]+rotatematrix[6]*v[1]+rotatematrix[10]*v[2]+rotatematrix[14]*w;
    ww=rotatematrix[3]*v[0]+rotatematrix[7]*v[1]+rotatematrix[11]*v[2]+rotatematrix[15]*w;
    v[0]=xx/ww; v[1]=yy/ww; v[2]=zz/ww;
  }

  template <typename T1>
  void RotateBack(T1 *rotatematrix)//column major 4x4
  {
    T w=1;
    T xx,yy,zz,ww;
    xx=rotatematrix[0]*v[0]+rotatematrix[1]*v[1]+rotatematrix[2]*v[2]+rotatematrix[3]*w;
    yy=rotatematrix[4]*v[0]+rotatematrix[5]*v[1]+rotatematrix[6]*v[2]+rotatematrix[7]*w;
    zz=rotatematrix[8]*v[0]+rotatematrix[9]*v[1]+rotatematrix[10]*v[2]+rotatematrix[11]*w;
    ww=rotatematrix[12]*v[0]+rotatematrix[13]*v[1]+rotatematrix[14]*v[2]+rotatematrix[15]*w;
    v[0]=xx/ww; v[1]=yy/ww; v[2]=zz/ww;
  }
};
typedef Cartesian3DCoord<float> Cartesian3DCoordf;

template <typename T>
struct CartesianDirCoord : public Vector<3,T>
{
  using Vector<3,T>::v;
  CartesianDirCoord():Vector<3,T>(){}
  CartesianDirCoord(const T& a,const T& b,const T& c):Vector<3,T>(a,b,c){}
  //Cartesian3DCoord
  template <typename T1>
  CartesianDirCoord(const Cartesian3DCoord<T1> &c)
  {
    *this=c;
  }
  template <typename T1>
  const CartesianDirCoord<T> &operator=(const Cartesian3DCoord<T1> &c)
  {
    v[0]=c.v[0]; v[1]=c.v[1]; v[2]=c.v[2];
    return *this;
  }
  //Vector3
  template <typename T1>
  CartesianDirCoord(const VectorBase<3,T1> &c)
  {
    *this=c;
  }
  template <typename T1>
  const CartesianDirCoord<T> &operator=(const VectorBase<3,T1> &c)
  {
    VectorBase<3,T>::operator =(c);
    return *this;
  }
  //SphericalCoord
  template <typename T1>
  const CartesianDirCoord<T> &operator =(const SphericalCoord<T1> &s)
  {
    v[0]=(T)s.rho*cos(s.phi)*sin(s.theta);
    v[1]=(T)s.rho*sin(s.phi)*sin(s.theta);
    v[2]=(T)s.rho*cos(s.theta);
    return *this;
  }

  template <typename T1>
  CartesianDirCoord(const SphericalCoord<T1> &s)
  {
    *this=s;
  }
  //CubeCoordNormalized
  template <typename T1>
  const CartesianDirCoord<T> &operator =(const CubeCoordNormalized<T1> &s)
  {
    switch(s.cubeface)
    {
    case POSX:
      v[0]=0.5f; v[1]=0.5f-s.v; v[2]=0.5f-s.u;
      break;
    case POSY:
      v[0]=-0.5f+s.u; v[1]=0.5f; v[2]=-0.5f+s.v;
      break;
    case POSZ:
      v[0]=-0.5f+s.u; v[1]=0.5f-s.v; v[2]=0.5f;
      break;
    case NEGX:
      v[0]=-0.5f; v[1]=0.5f-s.v; v[2]=-0.5f+s.u;
      break;
    case NEGY:
      v[0]=-0.5f+s.u; v[1]=-0.5f; v[2]=0.5f-s.v;
      break;
    case NEGZ:
      v[0]=0.5f-s.u; v[1]=0.5f-s.v; v[2]=-0.5f;
      break;
    default:
      break;
    }
    return *this;
  }

  template <typename T1>
  CartesianDirCoord(const CubeCoordNormalized<T1> &s)
  {
    *this=s;
  }
  //CubeCoord
  const CartesianDirCoord<T> &operator =(const CubeCoord &s)
  {
    T uu=(T)((s.x+0.5)/s.size),vv=(T)((s.y+0.5)/s.size);
    switch(s.cubeface)
    {
    case POSX:
      v[0]=0.5f; v[1]=0.5f-vv; v[2]=0.5f-uu;
      break;
    case POSY:
      v[0]=-0.5f+uu; v[1]=0.5f; v[2]=-0.5f+vv;
      break;
    case POSZ:
      v[0]=-0.5f+uu; v[1]=0.5f-vv; v[2]=0.5f;
      break;
    case NEGX:
      v[0]=-0.5f; v[1]=0.5f-vv; v[2]=-0.5f+uu;
      break;
    case NEGY:
      v[0]=-0.5f+uu; v[1]=-0.5f; v[2]=0.5f-vv;
      break;
    case NEGZ:
      v[0]=0.5f-uu; v[1]=0.5f-vv; v[2]=-0.5f;
      break;
    default:
      break;
    }
    Vector<3,T>::Normalize();
    return *this;
  }

  CartesianDirCoord(const CubeCoord &s)
  {
    *this=s;
  }
  //Rotate
  template <typename T1>
  void Rotate(T1 *rotatematrix)//column major 4x4
  {
    T xx,yy,zz;
    xx=rotatematrix[0]*v[0]+rotatematrix[4]*v[1]+rotatematrix[8]*v[2];
    yy=rotatematrix[1]*v[0]+rotatematrix[5]*v[1]+rotatematrix[9]*v[2];
    zz=rotatematrix[2]*v[0]+rotatematrix[6]*v[1]+rotatematrix[10]*v[2];
    v[0]=xx; v[1]=yy; v[2]=zz;
  }

  template <typename T1>
  void RotateBack(T1 *rotatematrix)//column major 4x4
  {
    T xx,yy,zz;
    xx=rotatematrix[0]*v[0]+rotatematrix[1]*v[1]+rotatematrix[2]*v[2];
    yy=rotatematrix[4]*v[0]+rotatematrix[5]*v[1]+rotatematrix[6]*v[2];
    zz=rotatematrix[8]*v[0]+rotatematrix[9]*v[1]+rotatematrix[10]*v[2];
    v[0]=xx; v[1]=yy; v[2]=zz;
  }

};
typedef CartesianDirCoord<float> CartesianDirCoordf;

template <typename T>
struct SphericalCoord
{
  T theta,phi,rho;

  SphericalCoord()
  {
    theta=phi=rho=(T)0;
  }

  SphericalCoord(const T _theta,const T _phi,const T _rho)
  {
    theta=_theta;phi=_phi;rho=_rho;
  }

  SphericalCoord(const T _theta,const T _phi)
  {
    theta=_theta;phi=_phi;rho=1.0;
  }

  //CartesianDirCoord
  template <typename T1> 
  const SphericalCoord<T> &operator =(const CartesianDirCoord<T1>& v)
  {
    rho=v.Len();
    theta=(T)acos(v.v[2]/rho);
    phi=(T)atan2(v.v[1],v.v[0]);
    return *this;
  }

  template <typename T1> 
  SphericalCoord(const CartesianDirCoord<T1>& v)
  {
    *this=v;
  }
  //Cartesian3DCoord
  template <typename T1> 
  const SphericalCoord<T> &operator =(const Cartesian3DCoord<T1>& v)
  {
    rho=v.len();
    theta=(T)acos(v.v[2]/rho);
    phi=(T)atan2(v.v[1],v.v[0]);
    return *this;
  }

  template <typename T1> 
  SphericalCoord(const Cartesian3DCoord<T1>& v)
  {
    *this=v;
  }
  //CubeCoordNormalized
  template <typename T1> 
  const SphericalCoord<T> &operator =(const CubeCoordNormalized<T1> &v)
  {
    VectorBase<3,T> tv(0,0,0);
    switch(v.cubeface)
    {
    case POSX:
      tv.v[0]=0.5f;tv.v[1]=0.5f-(T)v.v;tv.v[2]=0.5f-(T)v.u;
      break;
    case POSY:
      tv.v[0]=-0.5f+(T)v.u;tv.v[1]=0.5f;tv.v[2]=-0.5f+(T)v.v;
      break;
    case POSZ:
      tv.v[0]=-0.5f+(T)v.u;tv.v[1]=0.5f-(T)v.v;tv.v[2]=0.5f;
      break;
    case NEGX:
      tv.v[0]=-0.5f;tv.v[1]=0.5f-(T)v.v;tv.v[2]=-0.5f+(T)v.u;
      break;
    case NEGY:
      tv.v[0]=-0.5f+(T)v.u;tv.v[1]=-0.5f;tv.v[2]=0.5f-(T)v.v;
      break;
    case NEGZ:
      tv.v[0]=0.5f-(T)v.u;tv.v[1]=0.5f-(T)v.v;tv.v[2]=-0.5f;
      break;
    default:
      break;
    }
    rho=tv.len();
    theta=(T)acos(v.v[2]/rho);
    phi=(T)atan2(v.v[1],v.v[0]);
  }

  template <typename T1>
  SphericalCoord(const CubeCoordNormalized<T1> &v)
  {
    *this=v;
  }
  //CubeCoord
  const SphericalCoord<T> &operator =(const CubeCoord &other)
  {
    VectorBase<3,T> tv(0,0,0);
    T u=(T)((other.x+0.5)/other.size),v=(T)((other.x+0.5)/other.size);
    switch(v.cubeface)
    {
    case POSX:
      tv.v[0]=0.5f;tv.v[1]=0.5f-v;tv.v[2]=0.5f-u;
      break;
    case POSY:
      tv.v[0]=-0.5f+u;tv.v[1]=0.5f;tv.v[2]=-0.5f+v;
      break;
    case POSZ:
      tv.v[0]=-0.5f+u;tv.v[1]=0.5f-v;tv.v[2]=0.5f;
      break;
    case NEGX:
      tv.v[0]=-0.5f;tv.v[1]=0.5f-v;tv.v[2]=-0.5f+u;
      break;
    case NEGY:
      tv.v[0]=-0.5f+u;tv.v[1]=-0.5f;tv.v[2]=0.5f-v;
      break;
    case NEGZ:
      tv.v[0]=0.5f-u;tv.v[1]=0.5f-v;tv.v[2]=-0.5f;
      break;
    default:
      break;
    }
    rho=tv.len();
    theta=(T)acos(v.v[2]/rho);
    phi=(T)atan2(v.v[1],v.v[0]);
  }

  SphericalCoord(const CubeCoord &v)
  {
    *this=v;
  }
  //to Vector3
  template <typename T1>
  operator VectorBase<3,T1>()
  {
    return VectorBase<3,T1>(theta,phi,rho);
  }
};
typedef SphericalCoord<float> SphericalCoordf;

template <typename T>
struct CubeCoordNormalized
{
  CUBEFACE cubeface;
  T u,v;

  CubeCoordNormalized()
  {
    cubeface=POSX;
    u=0; v=0;
  }

  CubeCoordNormalized(const CUBEFACE _face, const T _x, const T _y)
  {
    cubeface=_face;
    u=_x; v=_y;
  }
  //CartesianDirCoord
  template <typename T1> 
  const CubeCoordNormalized<T> &operator=(const CartesianDirCoord<T1> &p1)
  {
    Cartesian3DCoord<T1> p=p1;
    T1 a=(T1)fabs(p.v[0]);
    if (a<fabs(p.v[1])) a=fabs(p.v[1]);
    if (a<fabs(p.v[2])) a=fabs(p.v[2]);
    p.v[0]/=a*2; p.v[1]/=a*2; p.v[2]/=a*2;
    if (fabs(p.v[0])>(T1)(0.5-EPS))
      if (p.v[0]>(T1)0.0)
        cubeface=POSX;
      else
        cubeface=NEGX;
    else

      if (fabs(p.v[1])>(T1)(0.5-EPS))
        if (p.v[1]>(T1)0.0)
          cubeface=POSY;
        else
          cubeface=NEGY;
      else
        if (p.v[2]>(T1)0.0)
          cubeface=POSZ;
        else
          cubeface=NEGZ;
    switch(cubeface)
    {
    case POSX:
      u=(T)(0.5-p.v[2]); v=(T)(0.5-p.v[1]);
      break;
    case POSY:
      u=(T)(0.5+p.v[0]); v=(T)(0.5+p.v[2]);
      break;
    case POSZ:
      u=(T)(0.5+p.v[0]); v=(T)(0.5-p.v[1]);
      break;
    case NEGX:
      u=(T)(0.5+p.v[2]); v=(T)(0.5-p.v[1]);
      break;
    case NEGY:
      u=(T)(0.5+p.v[0]); v=(T)(0.5-p.v[2]);
      break;
    case NEGZ:
      u=(T)(0.5-p.v[0]); v=(T)(0.5-p.v[1]);
      break;
    }
    return *this;
  }

  template <typename T1> 
  CubeCoordNormalized(const CartesianDirCoord<T1> &p)
  {
    *this=p; 
  }

  //Cartesian3DCoord
  template <typename T1> 
  const CubeCoordNormalized<T> &operator=(const Cartesian3DCoord<T1> &p1)
  {
    Cartesian3DCoord<T1> p=p1;
    T1 a=(T1)fabs(p.v[0]());
    if (a<fabs(p.v[1]())) a=fabs(p.v[1]());
    if (a<fabs(p.v[2]())) a=fabs(p.v[2]());
    p.v[0]()/=a*2; p.v[1]()/=a*2; p.v[2]()/=a*2;
    if (fabs(p.v[0]())>(T1)(0.5-EPS))
      if (p.v[0]()>(T1)0.0)
        cubeface=POSX;
      else
        cubeface=NEGX;
    else

      if (fabs(p.v[1]())>(T1)(0.5-EPS))
        if (p.v[1]()>(T1)0.0)
          cubeface=POSY;
        else
          cubeface=NEGY;
      else
        if (p.v[2]()>(T1)0.0)
          cubeface=POSZ;
        else
          cubeface=NEGZ;
    switch(cubeface)
    {
    case POSX:
      u=(T)(0.5-p.v[2]()); v=(T)(0.5-p.v[1]());
      break;
    case POSY:
      u=(T)(0.5+p.v[0]()); v=(T)(0.5+p.v[2]());
      break;
    case POSZ:
      u=(T)(0.5+p.v[0]()); v=(T)(0.5-p.v[1]());
      break;
    case NEGX:
      u=(T)(0.5+p.v[2]()); v=(T)(0.5-p.v[1]());
      break;
    case NEGY:
      u=(T)(0.5+p.v[0]()); v=(T)(0.5-p.v[2]());
      break;
    case NEGZ:
      u=(T)(0.5-p.v[0]()); v=(T)(0.5-p.v[1]());
      break;
    }
    return *this;
  }

  template <typename T1> 
  CubeCoordNormalized(const Cartesian3DCoord<T1> &p)
  {
    *this=p; 
  }
  //CubeCoord
  const CubeCoordNormalized<T> &operator=(const CubeCoord &p)
  {
    cubeface=p.cubeface;
    u=(T)((0.5+p.x)/p.size);
    v=(T)((0.5+p.y)/p.size);
    return *this;
  }

  CubeCoordNormalized(const CubeCoord &p)
  {
    *this=p;
  }
  //To CubeCoord
  CubeCoord ToCubeCoord(int size) const
  {
    return CubeCoord(cubeface,u*size,v*size,size);
  }
  CubeCoord GetBaseCubeCoord(int size,float &ratioX,float &ratioY) const
  {
    CubeCoord ret;
    ret.cubeface=cubeface;
    ret.size=size;

    float vcu=u,vcv=v;
    vcu=(vcu*size-0.5f)/(size-1.0f);
    vcv=(vcv*size-0.5f)/(size-1.0f);

    ret.x=(int)(vcu*(size-1)+size)-size;
    ret.y=(int)(vcv*(size-1)+size)-size;
    ratioX=vcu*(size-1)-ret.x;
    ratioY=vcv*(size-1)-ret.y;

    return ret;
  }

  //to Vector3
  template <typename T1>
  operator VectorBase<3,T1>()
  {
    return VectorBase<3,T1>(cubeface,u,v);
  }
};
typedef CubeCoordNormalized<float> CubeCoordNormalizedf;


}
